package org.hbgl.geoentity.admin.web.admin;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.hbgl.geoentity.admin.annotation.LoginLog;
import org.hbgl.geoentity.admin.annotation.OperationLog;
import org.hbgl.geoentity.admin.annotation.RequiresPermissionsDesc;
import org.hbgl.geoentity.admin.aspect.OperationType;
import org.hbgl.geoentity.admin.shiro.CustomLoginToken;
import org.hbgl.geoentity.admin.shiro.UserType;
import org.hbgl.geoentity.admin.web.BaseController;
import org.hbgl.geoentity.core.config.RRException;
import org.hbgl.geoentity.core.util.*;
import org.hbgl.geoentity.core.util.bcrypt.BCryptPasswordEncoder;
import org.hbgl.geoentity.db.domain.GeUser;
import org.hbgl.geoentity.db.vo.NodeVo;
import org.hbgl.geoentity.db.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static org.hbgl.geoentity.admin.util.ResponseCode.*;

@RestController
@RequestMapping("/admin/auth")
@Validated
public class AdminAuthController extends BaseController {
    @Autowired
    private AdminRoleController adminRoleController;

    /**
     * 登录
     *
     * @param body { username : 用户名, password : 密码 }
     */
    @LoginLog(detail = "登录", userType = UserType.ADMIN)
    @PostMapping("/login")
    public Object login(@RequestBody String body) {
        String username = JacksonUtil.parseString(body, "username");
        String password = JacksonUtil.parseString(body, "password");
        String code = JacksonUtil.parseString(body, "code");
        if (!ObjectUtils.allNotNull(username, password, code)) {
            return ResponseUtil.badArgument();
        }
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            return ResponseUtil.badArgumentValue();
        }
        if (StringUtils.isBlank(code)) {
            return ResponseUtil.fail(ADMIN_INVALID_KAPTCHA_REQUIRED, "验证码不能空");
        }
        if (!code.equalsIgnoreCase(getkaptcha())) {
            return ResponseUtil.fail(ADMIN_INVALID_KAPTCHA, "验证码不正确", doKaptcha());
        }
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(new CustomLoginToken(username, password, UserType.ADMIN));
        } catch (UnknownAccountException uae) {
            return ResponseUtil.fail(ADMIN_INVALID_ACCOUNT, "用户帐号或密码不正确", doKaptcha());
        } catch (LockedAccountException lae) {
            return ResponseUtil.fail(ADMIN_INVALID_ACCOUNT, "用户帐号已禁用", doKaptcha());
        } catch (RRException rre) {
            return ResponseUtil.fail(ADMIN_INVALID_ACCOUNT, rre.getMessage(), doKaptcha());
        } catch (AuthenticationException ae) {
            return ResponseUtil.fail(ADMIN_INVALID_ACCOUNT, "认证失败", doKaptcha());
        }
        GeUser userCurrent = getCurrentAdminUser();
        GeUser user = new GeUser();
        user.setId(userCurrent.getId());
        user.setLastLoginIp(IpUtil.getIpAddr(request));
        user.setLastLoginTime(LocalDateTime.now());
        if (userService.updateByIdSelective(user) == 0) {
            return ResponseUtil.updatedDataFailed();
        }

        // userInfo
        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("username", userCurrent.getUsername());
        userInfo.put("realname", userCurrent.getRealname());
        userInfo.put("sex", userCurrent.getSex());
        userInfo.put("telephone", userCurrent.getTelephone());
        userInfo.put("email", userCurrent.getEmail());
        Set<String> assignedPermissions = adminRoleController.getAssignedPermissions(userCurrent.getRoleId());

        Map<Object, Object> result = new HashMap<>();
        result.put("token", subject.getSession().getId());
        result.put("userInfo", userInfo);
        result.put("assignedPermissions", assignedPermissions);
        return ResponseUtil.ok(result);
    }

    /**
     * 获取验证码
     */
    @GetMapping("/kaptcha")
    public Object kaptcha() {
        String kaptcha = doKaptcha();
        if (kaptcha != null) {
            return ResponseUtil.ok(kaptcha);
        }
        return ResponseUtil.fail();
    }
    /**
     * 退出
     */
    @RequiresAuthentication
    @PostMapping("/logout")
    public Object logout() {
        Subject subject = SecurityUtils.getSubject();

        subject.logout();
        return ResponseUtil.ok();
    }

    /**
     * 获取当前账号信息
     */
    @RequiresAuthentication
    @GetMapping("/info")
    public Object info() {
        GeUser userCurrent = getCurrentAdminUser();

        UserVo user = userService.selectUserById(userCurrent.getUnitId(), userCurrent.getId());
        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("username", user.getUsername());
        userInfo.put("realname", user.getRealname());
        userInfo.put("sex", user.getSex());
        userInfo.put("telephone", user.getTelephone());
        userInfo.put("email", user.getEmail());

        Map<Object, Object> result = new HashMap<>();
        result.put("userInfo", userInfo);
        return ResponseUtil.ok(result);
    }

    /**
     * 编辑当前账号信息
     *
     * @param user 账号信息
     */
    @RequiresPermissions("admin:auth:update")
    @RequiresPermissionsDesc(menu = {"授权管理", "账号信息"}, button = "编辑")
    @OperationLog(detail = "编辑当前账号信息", operationType = OperationType.UPDATE, userType = UserType.ADMIN)
    @PostMapping("/update")
    public Object update(@RequestBody GeUser user) {
        GeUser userCurrent = getCurrentAdminUser();

        user.setId(userCurrent.getId());

        if (userService.updateByIdSelective(user) == 0) {
            return ResponseUtil.updatedDataFailed();
        }

        return ResponseUtil.ok();
    }

    /**
     * 修改当前账号密码
     *
     * @param body { oldPassword : 原密码, newPassword : 新密码 }
     */
    @OperationLog(detail = "修改当前账号密码", operationType = OperationType.UPDATE, userType = UserType.ADMIN)
    @PostMapping("/password")
    public Object password(@RequestBody String body) {
        String oldPassword = JacksonUtil.parseString(body, "oldPassword");
        String newPassword = JacksonUtil.parseString(body, "newPassword");
        if (!ObjectUtils.allNotNull(oldPassword, newPassword)) {
            return ResponseUtil.badArgument();
        }
        if (newPassword.length() < 6) {
            return ResponseUtil.fail(ADMIN_INVALID_PASSWORD, "密码长度不能小于6");
        }

        GeUser userCurrent = getCurrentAdminUser();

        GeUser userLatest = userService.findPasswordById(userCurrent.getId());

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(oldPassword, userLatest.getPassword())) {
            return ResponseUtil.fail(ADMIN_INVALID_ACCOUNT, "原密码输入错误");
        }

        GeUser user = new GeUser();
        user.setId(userCurrent.getId());
        user.setPassword(encoder.encode(newPassword));

        if (userService.updateByIdSelective(user) == 0) {
            return ResponseUtil.updatedDataFailed();
        }

        return ResponseUtil.ok();
    }

    /**
     * 首页信息
     */
    @RequiresAuthentication
    @GetMapping("/homeInfo")
    public Object homeInfo() {
        GeUser userCurrent = getCurrentAdminUser();

        UserVo user = userService.selectUserById(userCurrent.getUnitId(), userCurrent.getId());
        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("username", user.getUsername());
        userInfo.put("realname", user.getRealname());
        userInfo.put("sex", user.getSex());
        userInfo.put("telephone", user.getTelephone());
        userInfo.put("email", user.getEmail());

        String greeting = GreetingMaker.printTimeOfDay();
        userInfo.put("greeting", greeting);

        Long nodeCount = nodeService.selectNodeCount();
        userInfo.put("nodecount", nodeCount - 1L);

        Long unitCount = unitService.selectUnitCount();
        userInfo.put("unitcount", unitCount - 1L);

        Map<Object, Object> result = new HashMap<>();
        result.put("userInfo", userInfo);
        return ResponseUtil.ok(result);
    }

    /**
     * 当前账号信息授权信息
     */
    @RequiresPermissions("admin:auth:authinfo")
    @RequiresPermissionsDesc(menu = {"授权管理", "授权信息"}, button = "查看")
    @OperationLog(detail = "查看账号授权信息", operationType = OperationType.SELECT, userType = UserType.ADMIN)
    @PostMapping("/authInfo")
    public Object authInfo() {
        GeUser userCurrent = getCurrentAdminUser();
        Integer userId = userCurrent.getUnitId();
        NodeVo nodeVo = userService.selectUserAuthByUnitId(userId);
        if (nodeVo == null) {
            return ResponseUtil.fail();
        }
        return ResponseUtil.ok(nodeVo);
    }

}
